#include "Client.h"
#include <iostream>
#include <vector>
#include "DataContainer.h"
#include "PFileInfo.h"
#include "SingletonHolder.h"
#include <boost/lexical_cast.hpp>

namespace btcp = boost::asio::ip;

Client::Client(std::string& theAdress,std::string& thePort) : myConnection(myIo_service)
{
	
	myAdress = theAdress;
	myPort = thePort;
	myConnected = false;
}


void Client::Connect()
{
	btcp::tcp::resolver resolver(myIo_service);
	btcp::tcp::resolver::query query(myAdress,myPort);
	btcp::tcp::resolver::iterator endpoint_iter = resolver.resolve(query);
	btcp::tcp::endpoint endpoint = *endpoint_iter;

	myConnection.GetSocket().async_connect(endpoint,boost::bind(&Client::handle_connect,shared_from_this(),boost::asio::placeholders::error,++endpoint_iter));
	myIo_service.run();
}


void Client::handle_connect(const boost::system::error_code &er, boost::asio::ip::tcp::resolver::iterator endpoint_iter)
{
	if(!er)  //spojenie uspesne
	{
		myConnected = true;
		return;
	}
	else if(endpoint_iter != btcp::tcp::resolver::iterator()) //skusime sa pripojit na dalsi endpoint
	{
		myConnected = false;
		myConnection.GetSocket().close();
		btcp::tcp::endpoint endpoint = *endpoint_iter;
		myConnection.GetSocket().async_connect(endpoint,boost::bind(&Client::handle_connect,shared_from_this(),boost::asio::placeholders::error,++endpoint_iter));
	}
	else
	{
		myConnected = false;
		SingletonHolder::Instance().WriteEx("Cant connect to the conversion server!");
	}
}

bool Client::IsConnected()
{
	return myConnected;
}

void Client::Write(PComunicator::DataContainer &theContainer)
{
	std::vector<unsigned char> output;
	theContainer.GenerateOutput(output);

	std::string thesize = boost::lexical_cast<std::string>(output.size());

	if(myConnected)
	{
		boost::asio::write(myConnection.GetSocket(),boost::asio::buffer(thesize)); //synchronne posielanie 
		
		std::size_t senddata = boost::asio::write(myConnection.GetSocket(),boost::asio::buffer(output));
		
		// Temporary [2/6/2010 psicho]
		myConnection.GetSocket().close();
		//------------------------------
		if(senddata != output.size())
		{
			SingletonHolder::Instance().WriteEx("Client:	Error sending data...not all data has been transmited");
		}

		/*if(output.size() > 8192)
		{
			write_data(output);
		}
		else
		{
			boost::asio::write(myConnection.GetSocket(),boost::asio::buffer(output));
		}*/
	}
}

void Client::write_data(std::vector<unsigned char> &input)
{
	std::size_t downIndex = 0;
	std::size_t upIndex = 0;

	while( upIndex < input.size() -1 )
	{
		std::vector<char> buffer;

		upIndex += 8192;

		if(upIndex >= input.size())
		{
			int aLeftOver = upIndex - (input.size()-1);
			if(aLeftOver != 0 )
			{
				copy(input,downIndex+1,aLeftOver-1,buffer);
				//myIo_service.run();
			}
		}
		else
		{
			copy(input,downIndex,upIndex,buffer);
		}

		//std::size_t writen = myConnection.GetSocket().write_some(boost::asio::buffer(buffer));
		boost::asio::write(myConnection.GetSocket(),boost::asio::buffer(buffer));

		downIndex = upIndex + 1;
	}
}


void Client::copy(std::vector<unsigned char> input,std::size_t down_index,std::size_t up_index, std::vector<char> &output)
{
	for(std::size_t i= down_index; i < up_index; i++)
	{
		output.push_back(input[i]);
	}
}


void Client::Read()
{
	/* NOT IMPLEMENTED */
}